package com.ksyun.start.camp.controller;

import com.ksyun.start.camp.model.ApiResponse;
import com.ksyun.start.camp.model.HeartInstance;
import com.ksyun.start.camp.model.ServiceInstance;
import com.ksyun.start.camp.model.vo.ServiceInstanceVO;
import com.ksyun.start.camp.utils.BeanCopyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api")
@Slf4j
public class RegistryController {

    // 服务注册信息存储在 Map 中，键为服务名，值为该服务名下的服务实例列表
    private Map<String, List<ServiceInstance>> registry = new ConcurrentHashMap<>();

    // 定义服务实例的过期时间，单位为秒，这里设置为 60 秒
    private static final int EXPIRATION_TIME_SECONDS = 60;

    // 用于定时检查过期服务实例的线程池
    private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);

    @PostMapping("/register")
    public ApiResponse registerService(@RequestBody ServiceInstance serviceInstance) {
        serviceInstance.setLastHeartbeatTime(LocalDateTime.now());
        String serviceName = serviceInstance.getServiceName();
        List<ServiceInstance> serviceInstances = registry.computeIfAbsent(serviceName, k -> new ArrayList<>());

        // 判断是否已经存在相同的服务实例
        if (serviceInstances.stream().anyMatch(existingInstance -> existingInstance.getServiceId().equals(serviceInstance.getServiceId()))) {
            return new ApiResponse<>(501, "注册失败，该服务ID对应的服务已存在");
        }

        // 注册服务实例并开始定时检查心跳
        serviceInstances.add(serviceInstance);
        startHeartbeatCheck(serviceName);
        return new ApiResponse<>(200, "注册成功");
    }

    @PostMapping("/unregister")
    public ApiResponse unregisterService(@RequestBody ServiceInstance serviceInstance) {
        boolean unregistered = unregister(serviceInstance);
        if (unregistered) {
            return new ApiResponse<>(200, "注销成功");
        } else {
            return new ApiResponse<>(502, "注销失败，没有找到匹配的服务实例");
        }
    }


    private final Map<String, AtomicInteger> currentIndexMap = new ConcurrentHashMap<>();
    private final Map<String, Integer> lastReturnedIndexMap = new ConcurrentHashMap<>();
    @GetMapping("/discovery")
    public ApiResponse<List<ServiceInstanceVO>> discoverServices(@RequestParam(required = false) String name) {
        // 保证各个服务互不干扰
        currentIndexMap.putIfAbsent(name, new AtomicInteger(0));

        // 带负载均衡的、指定名称的应用发现
        if (!StringUtils.isEmpty(name) && registry.containsKey(name)) {
            List<ServiceInstance> serviceInstances = registry.get(name);
            List<ServiceInstanceVO> serviceInstanceVOS = BeanCopyUtils.copyBeanList(serviceInstances, ServiceInstanceVO.class);
            // 实现轮询
            int currentIndex = Math.abs(currentIndexMap.get(name).getAndIncrement() % serviceInstances.size());
            // 记录上一次返回的索引
            int lastReturnedIndex = lastReturnedIndexMap.getOrDefault(name, -1);
            // 避免两次返回相同的索引，确保不同节点信息
            if (currentIndex == lastReturnedIndex) {
                currentIndex = (currentIndex + 1) % serviceInstances.size();
            }
            lastReturnedIndexMap.put(name, currentIndex);
            ServiceInstanceVO serviceInstanceVO = serviceInstanceVOS.get(currentIndex);
            // 封装返回结果
            List<ServiceInstanceVO> result = new ArrayList<>();
            result.add(serviceInstanceVO);
            return new ApiResponse<>(200, result);
        } else {
            // 不带 name 参数调用时，返回所有正常可用的服务列表
            List<ServiceInstance> serviceInstances = registry.values().stream()
                    .flatMap(List::stream)
                    .filter(this::isServiceInstanceActive) // 过滤掉过期的服务实例
                    .collect(Collectors.toList());
            List<ServiceInstanceVO> serviceInstanceVOS = BeanCopyUtils.copyBeanList(serviceInstances, ServiceInstanceVO.class);
            return new ApiResponse<>(200, serviceInstanceVOS);
        }
    }

    @PostMapping("/heartbeat")
    public ApiResponse sendHeartbeat(@RequestBody HeartInstance heartInstance) {
        String id = heartInstance.getServiceId();
        //遍历拿到所有实例
        List<ServiceInstance> serviceInstances=new ArrayList<>();
        Set<Map.Entry<String, List<ServiceInstance>>> entries = registry.entrySet();
        Iterator<Map.Entry<String, List<ServiceInstance>>> iterator = entries.iterator();
        log.info("--"+id+"的心跳请求开始,此时时间为"+LocalDateTime.now()+",注册中心所含服务如下:---------");
        while(iterator.hasNext()){
            Map.Entry<String, List<ServiceInstance>> entry = iterator.next();
            List<ServiceInstance> instances = entry.getValue();
            for (ServiceInstance instance :instances) {
                serviceInstances.add(instance);
                log.info(String.valueOf(instance));
            }
        }

        if (serviceInstances != null) {
            for (ServiceInstance instance : serviceInstances) {
                String serviceId = instance.getServiceId();
                String ipAddress = instance.getIpAddress();
                Integer port = instance.getPort();
                String serviceInstanceServiceId = heartInstance.getServiceId();
                String serviceInstanceIpAddress = heartInstance.getIpAddress();
                Integer serviceInstancePort = heartInstance.getPort();
                //找到请求所对应的实例
                if (serviceId.equals(serviceInstanceServiceId)
                        && ipAddress.equals(serviceInstanceIpAddress)
                        && port.equals(serviceInstancePort))
                {
                    log.info("--"+id+"的心跳请求结束,更新上一次时间为"+LocalDateTime.now()+"---------");
                    // 更新心跳时间
                    instance.setLastHeartbeatTime(LocalDateTime.now());
                    return new ApiResponse<>(200, "心跳更新成功");
                }
            }
        }
        return new ApiResponse<>(503, "心跳更新失败，未找到对应的服务实例或该服务心跳超时");
    }

    // 启动心跳检查定时任务
    private void startHeartbeatCheck(String serviceName) {
        executorService.scheduleWithFixedDelay(() -> {
            //先获得该服务的实例
            List<ServiceInstance> serviceInstances = registry.getOrDefault(serviceName, new ArrayList<>());
            //检测服务是否还有心跳传来，没有则注销
            for (ServiceInstance serviceInstance : serviceInstances) {
                if (!RegistryController.this.isServiceInstanceActive(serviceInstance)) {//心跳超时
                    RegistryController.this.unregister(serviceInstance);
                }
            }
        }, 0, // 初始延迟时间，第一次执行任务的延迟时间，单位为秒
                EXPIRATION_TIME_SECONDS, // 两次任务之间的执行间隔，单位为秒
                TimeUnit.SECONDS // 延迟时间和执行间隔的时间单位
        );
    }

    // 判断服务实例是否处于活跃状态（根据最后心跳时间判断）
    private boolean isServiceInstanceActive(ServiceInstance serviceInstance) {
        log.info("当前检测时间:{},"+serviceInstance.getServiceId()+"的心跳时间:{}",LocalDateTime.now(),serviceInstance.getLastHeartbeatTime());
        return LocalDateTime.now().isBefore(serviceInstance.getLastHeartbeatTime().plusSeconds(EXPIRATION_TIME_SECONDS));
    }

    // 注销服务,真正的注销成功才返回true
    private boolean unregister(ServiceInstance serviceInstance) {
        String serviceName = serviceInstance.getServiceName();

        List<ServiceInstance> serviceInstances = registry.get(serviceName);
        boolean isDel=false;//记录是否有服务被删除
        if (serviceInstances != null) {
            // 遍历服务实例列表，查找并移除匹配的实例
            Iterator<ServiceInstance> iterator = serviceInstances.iterator();
            while (iterator.hasNext()) {
                ServiceInstance instance = iterator.next();
                if (instance.getServiceId().equals(serviceInstance.getServiceId()) &&
                        instance.getIpAddress().equals(serviceInstance.getIpAddress()) &&
                        instance.getPort().equals(serviceInstance.getPort())) {
                    iterator.remove();
                    isDel=true;
                }
            }
            if (serviceInstances.isEmpty()) {
                registry.remove(serviceName);
            }
            return isDel; // 注销成功
        } else {//该服务名对应的实例找不到
            return isDel; // 注销失败
        }
    }

}

